#include "RomanNumeral.hpp"
#include "Integer.hpp"
#include <iostream>

RomanNumeral::RomanNumeral(std::string s):
	roman(s)
{
	parse();
}

RomanNumeral::RomanNumeral():
	word("")
{
	parse();
}


bool RomanNumeral::parse()
{
	std::string tempWord = word;
	integer = toIntegerOperation(tempWord);
	if ( integer == -1 )
	{
		word = "INVALID";
		roman = "INVALID";
		return false;
	}
	word = toWordNumberOperation(tempWord);
	return true;
}

bool RomanNumeral::startState()
{
	charPointer++;
    if ( tempRoman[charPointer] == 'M' ) return MState();
    else if ( tempRoman[charPointer] == 'D' ) return DState();
    else if ( tempRoman[charPointer] == 'C' ) return CState(1);
    else if ( tempRoman[charPointer] == 'L' ) return LState();
    else if ( tempRoman[charPointer] == 'X' ) return XState(1);
    else if ( tempRoman[charPointer] == 'V' ) return VState();
    else if ( tempRoman[charPointer] == 'I' ) return IState(1);
    else if ( tempRoman[charPointer] == 'Z' )
	{
		integer = 0;
		return true;
	}
	else return false;
}

bool RomanNumeral::MState()
{
	charPointer++;
    if ( tempRoman[charPointer] == 'Z' )
	{
        integer = 1000;
        return true;
	}
	else
		return false;
}

bool RomanNumeral::DState()
{
	charPointer++;
    integer+=500;
    if ( tempRoman[charPointer] == 'C' ) return CState(1);
    else if ( tempRoman[charPointer] == 'L' ) return LState();
    else if ( tempRoman[charPointer] == 'X' ) return XState(1);
    else if ( tempRoman[charPointer] == 'V' ) return VState();
    else if ( tempRoman[charPointer] == 'I' ) return IState(1);
    else if ( tempRoman[charPointer] == 'Z' ) return true;
	else return false;
}

bool RomanNumeral::CState(int repeat)
{
	charPointer++;
	integer+=100;

    if ( repeat > 3 )
	{
		return false;
	}

	if ( tempRoman[charPointer] == 'D' )
	{
        if ( repeat > 1 ) return false;
		else return DPostCState();
	}
	else if ( tempRoman[charPointer] == 'M' )
    {
        if ( repeat > 1 ) return false;
        else return MPostCState();
    }
	else if ( tempRoman[charPointer] == 'C' ) return CState(repeat+1);
	else if ( tempRoman[charPointer] == 'L' ) return LState();
	else if ( tempRoman[charPointer] == 'X' ) return XState(1);
	else if ( tempRoman[charPointer] == 'V' ) return VState();
	else if ( tempRoman[charPointer] == 'I' ) return IState(1);
	else if ( tempRoman[charPointer] == 'Z' ) return true;
	else return false;
}

bool RomanNumeral::LState()
{
	charPointer++;
    integer+=50;
	if ( tempRoman[charPointer] == 'X' ) return XState(1);
	else if ( tempRoman[charPointer] == 'V' ) return VState();
	else if ( tempRoman[charPointer] == 'I' ) return IState(1);
	else if ( tempRoman[charPointer] == 'Z' ) return true;
	else return false;
}

bool RomanNumeral::XState(int repeat)
{
	charPointer++;
	integer+=10;

    if ( repeat > 3 )
	{
		return false;
	}

	if ( tempRoman[charPointer] == 'C' )
	{
        if ( repeat > 1 )  return false;
		else return CPostXState();
	}
	else if ( tempRoman[charPointer] == 'L' )
	{
        if ( repeat > 1 )  return false;
		else return LPostXState();
	}
	else if ( tempRoman[charPointer] == 'X' ) return XState(repeat+1);
	else if ( tempRoman[charPointer] == 'V' ) return VState();
	else if ( tempRoman[charPointer] == 'I' ) return IState(1);
	else if ( tempRoman[charPointer] == 'Z' ) return true;
	else return false;
}

bool RomanNumeral::VState()
{
	charPointer++;
    integer+=5;
	if ( tempRoman[charPointer] == 'I' ) return IState(1);
	else if ( tempRoman[charPointer] == 'Z' ) return true;
	else return false;

}

bool RomanNumeral::IState(int repeat)
{
	charPointer++;
	integer+=1;

    if ( repeat > 3 )
	{
		return false;
	}

	if ( tempRoman[charPointer] == 'X' )
	{
        if ( repeat > 1 )  return false;
		else return XPostIState();
	}
	else if ( tempRoman[charPointer] == 'V' )
	{
        if ( repeat > 1 )  return false;
		else return VPostIState();
	}
	else if ( tempRoman[charPointer] == 'I' ) return IState(repeat+1);
	else if ( tempRoman[charPointer] == 'Z' )
	{
		return true;
	}
	else return false;
}

bool RomanNumeral::MPostCState()
{
	charPointer++;
	integer+=800;

	if ( tempRoman[charPointer] == 'L' ) return LState();
	else if ( tempRoman[charPointer] == 'X' ) return XState(1);
	else if ( tempRoman[charPointer] == 'V' ) return VState();
	else if ( tempRoman[charPointer] == 'I' ) return IState(1);
	else if ( tempRoman[charPointer] == 'Z' ) return true;
	else return false;
}

bool RomanNumeral::DPostCState()
{
	charPointer++;
	integer+=300;

	if ( tempRoman[charPointer] == 'L' ) return LState();
	else if ( tempRoman[charPointer] == 'X' ) return XState(1);
	else if ( tempRoman[charPointer] == 'V' ) return VState();
	else if ( tempRoman[charPointer] == 'I' ) return IState(1);
	else if ( tempRoman[charPointer] == 'Z' ) return true;
	else return false;
}

bool RomanNumeral::CPostXState()
{
	charPointer++;
	integer+=80;

	if ( tempRoman[charPointer] == 'V' ) return VState();
	else if ( tempRoman[charPointer] == 'I' ) return IState(1);
	else if ( tempRoman[charPointer] == 'Z' ) return true;
	else return false;
}

bool RomanNumeral::LPostXState()
{
	charPointer++;
	integer+=30;

	if ( tempRoman[charPointer] == 'V' ) return VState();
	else if ( tempRoman[charPointer] == 'I' ) return IState(1);
	else if ( tempRoman[charPointer] == 'Z' ) return true;
	else return false;
}

bool RomanNumeral::XPostIState()
{
	charPointer++;
	integer+=8;

	if ( tempRoman[charPointer] == 'Z' ) return true;
	else return false;
}

bool RomanNumeral::VPostIState()
{
	charPointer++;
	integer+=3;

	if ( tempRoman[charPointer] == 'Z' ) return true;
	else return false;
}

int RomanNumeral::toIntegerOperation(std:: string s)
{
	integer = 0;
	charPointer = 0;
	tempRoman = "A" + roman + "Z";

	if ( !startState() )
		return -1;
	else
		return integer;
}

std::string RomanNumeral::toWordNumberOperation(std:: string s)
{
	Integer i(integer);
	return i.toWordNumber();
}

int RomanNumeral::toInteger() const
{
	return integer;
}

std::string RomanNumeral::toRomanNumeral() const
{
    Integer a(integer);

    return a.toRomanNumeral();


}

std::string RomanNumeral::toWordNumber() const
{
    Integer i(integer);
	return i.toWordNumber();

}

RomanNumeral RomanNumeral::operator+(const RomanNumeral& rhs) const
{
	RomanNumeral lhs = *this;
	int x = lhs.integer + rhs.integer;
	if (lhs.integer < 0 || rhs.integer < 0 || x > 1000)
	{
		lhs.integer = -1;
		lhs.word = "INVALID";
		lhs.roman = "INVALID";
		return lhs;
	}
	lhs.integer = x;
	Integer i(lhs.integer);
	lhs.word = i.toWordNumber();
	lhs.roman = i.toRomanNumeral();

	return lhs;
}
RomanNumeral RomanNumeral::operator-(const RomanNumeral& rhs) const
{
	RomanNumeral lhs = *this;
	int x = lhs.integer - rhs.integer;
	if (lhs.integer < 0 || rhs.integer < 0 || x < 0)
	{
		lhs.integer = -1;
		lhs.word = "INVALID";
		lhs.roman = "INVALID";
		return lhs;
	}
	x = lhs.integer - rhs.integer;
	Integer i(lhs.integer);
	lhs.word = i.toWordNumber();
	lhs.roman = i.toRomanNumeral();

	return lhs;
}
RomanNumeral RomanNumeral::operator*(const RomanNumeral& rhs) const
{
	RomanNumeral lhs = *this;
	int x = lhs.integer * rhs.integer;
	if (lhs.integer < 0 || rhs.integer < 0 || x > 1000)
	{
		lhs.integer = -1;
		lhs.word = "INVALID";
		lhs.roman = "INVALID";
		return lhs;
	}
	lhs.integer = x;
	Integer i(lhs.integer);
	lhs.word = i.toWordNumber();
	lhs.roman = i.toRomanNumeral();

	return lhs;
}
RomanNumeral RomanNumeral::operator/(const RomanNumeral& rhs) const
{
	RomanNumeral lhs = *this;
	if (lhs.integer < 0 || rhs.integer < 0 || rhs.integer == 0)
	{
		lhs.integer = -1;
		lhs.word = "INVALID";
		lhs.roman = "INVALID";
		return lhs;
	}
	lhs.integer = lhs.integer / rhs.integer;
	Integer i(lhs.integer);
	lhs.word = i.toWordNumber();
	lhs.roman = i.toRomanNumeral();

	return lhs;
}
RomanNumeral RomanNumeral::operator%(const RomanNumeral& rhs) const
{
	RomanNumeral lhs = *this;
	if (lhs.integer < 0 || rhs.integer < 0)
	{
		lhs.integer = -1;
		lhs.word = "INVALID";
		lhs.roman = "INVALID";
		return lhs;
	}
	lhs.integer = lhs.integer % rhs.integer;
	Integer i(lhs.integer);
	lhs.word = i.toWordNumber();
	lhs.roman = i.toRomanNumeral();

	return lhs;
}

bool RomanNumeral::operator>(const RomanNumeral& rhs) const
{
	RomanNumeral lhs = *this;
	if ((lhs.integer == -1 && rhs.integer != -1) ||
		(lhs.integer != -1 && rhs.integer == -1))
	{
		return false;
	}
	return lhs.integer > rhs.integer;
}
bool RomanNumeral::operator<(const RomanNumeral& rhs) const
{
	RomanNumeral lhs = *this;
	if ((lhs.integer == -1 && rhs.integer != -1) ||
		(lhs.integer != -1 && rhs.integer == -1))
	{
		return false;
	}
	return lhs.integer < rhs.integer;
}
bool RomanNumeral::operator>=(const RomanNumeral& rhs) const
{
	RomanNumeral lhs = *this;
	if ((lhs.integer == -1 && rhs.integer != -1) ||
		(lhs.integer != -1 && rhs.integer == -1))
	{
		return false;
	}
	return lhs.integer >= rhs.integer;
}
bool RomanNumeral::operator<=(const RomanNumeral& rhs) const
{
	RomanNumeral lhs = *this;
	if ((lhs.integer == -1 && rhs.integer != -1) ||
		(lhs.integer != -1 && rhs.integer == -1))
	{
		return false;
	}
	return lhs.integer <= rhs.integer;
}
bool RomanNumeral::operator==(const RomanNumeral& rhs) const
{
	RomanNumeral lhs = *this;
	return lhs.integer == rhs.integer;
}


bool RomanNumeral::operator!=(const RomanNumeral& rhs) const
{
	RomanNumeral lhs = *this;
	return lhs.integer != rhs.integer;
}
